import datetime
import logging
import os
import random
# smtplib 用于邮件的发信动作
import smtplib
import ssl
import string
import traceback
# email 用于构建邮件内容
# 构建邮件头
from email.message import EmailMessage
from email.mime.text import MIMEText

import numpy as np
import requests
from PIL import Image, ImageDraw, ImageFont
from skimage import io

from config import STATIC_PATH, CODE_PATH
from util import error_res, ErrorCode
from util.exception_handlers import LoginCodeExceptionHandler, LoginCodeException

code_dict = dict()


def create_code():
    width, height, font_size, font_num = 300, 100, 48, 4
    bg_color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
    image = Image.new(mode='RGB', size=(width, height), color=bg_color)
    draw = ImageDraw.Draw(image, mode='RGB')
    font = ImageFont.truetype(f"{STATIC_PATH}/arial.ttf", font_size)
    verify = str()
    for i in range(font_num):
        x = random.randint(i * (width / font_num), (i + 1) * (width / font_num) - font_size)
        y = random.randint(0, height - font_size)
        char = random.choice([chr(alpha) for alpha in range(65, 91)] + [str(num) for num in range(10)])
        verify += char
        color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
        draw.text((x, y), char, fill=color, font=font)
    logging.info("验证码是: " + verify)
    return verify, image


def save_code(ip, verify, image):
    code_dict.update({
        ip: {
            "verify": verify,
            "create_time": datetime.datetime.utcnow()
        }
    })
    path = f"{CODE_PATH}/{ip}.png"
    io.imsave(path, np.array(image))
    logging.info("code_dict: " + str(code_dict))
    return path


def get_code(ip):
    info = code_dict.get(ip)
    if info is None:
        raise LoginCodeException("不存在")
    else:
        create_time = info.get("create_time")
        now = datetime.datetime.utcnow()
        difference = now - create_time
        if difference > datetime.timedelta(minutes=5):
            raise LoginCodeException("超时")
        else:
            return info.get("verify")

